package v2;

import java.awt.Color;

/**
 * @author bosc & dunoyerd
 * @version 0.1
 * @see
 * @since version 0.1
 */
public abstract class Entite {


	// Attributs

	/**
	 * La Quantité maximum d'eau que peux contenir l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int maxEau;

	/**
	 * La Quantité minimum d'eau que peux contenir l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int minEau;

	/**
	 * La Santé maximum de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int maxSante;

	/**
	 * Le facteur de perte d'eau de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int facteurPerteEau;

	/**
	 * La couleur de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private Color Couleur; // la couleur de l'entité

	/**
	 * La capacité de regénération de vie de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int gainSante;

	/**
	 * La santé actuelle de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position)
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int sante;

	/**
	 * La quantité actuelle d'eau dans l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position)
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int jaugeEau;

	/**
	 * La Position actuelle de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position)
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private Position maPosition;

	/** 
	 * La duree de vie de l'entité.
	 * 
	 * @see Entite#Entite(int,int,Position,int,int,int,int,Color,int,int)
	 */
	private int dureeVie;

	// Constructeurs

	/**
	 * Constructeur Entite.
	 * 
	 * Ce constructeur permet de ceer un objet Entite. Il prend en entrée une
	 * santé, une jauge d'eau et une Position.
	 * 
	 * @param maSante
	 *            La Santé de l'entité.
	 * @param maJaugeEau
	 *            La quantité d'eau de l'entité.
	 * @param maPosition
	 *            La Position de l'entité.
	 * 
	 * @see Entite#maSante
	 * @see Entite#maJaugeEau
	 * @see Entite#maPosition
	 */
	public Entite(int maSante, int maJaugeEau, Position maPosition) {
		this.sante = maSante;
		this.jaugeEau = maJaugeEau;
		this.maPosition = maPosition;
	}

	/**
	 * Constructeur Entite.
	 * 
	 * Ce constructeur permet de ceer un objet Entite. Il prend en entrée une
	 * santé, une jauge d'eau, une Position, un maxEau, un minEau, un MaxSanté,
	 * un facteur de perte d'eau, une couleur, un facteur de gain de santé et une durée de vie.
	 * 
	 * @param maSante
	 *            La Santé de l'entité.
	 * @param maJaugeEau
	 *            La quantité d'eau de l'entité.
	 * @param maPosition
	 *            La Position de l'entité.
	 * @param monMaxEau
	 *            La quantité d'eau maximum de l'entité
	 * @param monminEau
	 *            La quantité d'eau minimu de l'entité
	 * @param monMaxSante
	 *            La quantité de santé maximum de l'entité
	 * @param monFacteurPerteEau
	 *            Le facteur de perte d'eau de l'entité
	 * @param maCouleur
	 *            La couleur de l'entité
	 * @param monGainSante
	 *            Le gain de santé qu'obtient l'entité
	 * @param maDureeVie
	 * 			  La durée de vie de l'entité	 * 
	 * 
	 * @see Entite#maSante
	 * @see Entite#maJaugeEau
	 * @see Entite#maPosition
	 * @see Entite#monMaxEau
	 * @see Entite#monMinEau
	 * @see Entite#monMaxSante
	 * @see Entite#monfacteurPerteEau
	 * @see Entite#maCouleur
	 * @see Entite#monGainSante
	 * @see Entite#maDureeVie
	 */
	public Entite(int maSante, int maJaugeEau, Position maPosition,
			int monMaxEau, int monMinEau, int monMaxSante,
			int monFacteurPerteEau, Color maCouleur, int monGainSante,
			int maDureeVie) {
		
		// Santé
		this.maxSante = monMaxSante;
		if (this.maxSante<maSante)
		{
			maSante = this.maxSante;
		}
		this.sante = maSante;
		this.gainSante = monGainSante;
		
		// Eau
		// NB: on présupose que toute entité est crée avec des valeurs en eau "bonnes"
		this.maxEau = monMaxEau;
		this.minEau = monMinEau;
		this.facteurPerteEau = monFacteurPerteEau;
		if ((maJaugeEau<=monMaxEau) && (maJaugeEau>=monMinEau))
		{
			this.jaugeEau = maJaugeEau;
		}
		else
		{
			if (maJaugeEau>monMaxEau)
			{
				this.jaugeEau = monMaxEau;
			}
			else
			{
				this.jaugeEau = monMinEau;
			}
		}

		// Autres
		this.maPosition = maPosition;
		this.Couleur = maCouleur;
		this.dureeVie = maDureeVie;
	}

	// -------------
	// Accesseurs //
	// -------------
	
	// "Getteurs"

	/**
	 * Retourne la position de l'entité
	 * 
	 * @return la position de l'entité
	 */
	public Position obtientPosition() {
		return maPosition;
	}

	/**
	 * Retourne la quantité maximale en eau de l'entité.
	 * 
	 * @return la quantité maximale en eau de l'entité
	 */
	public int obtientMaxEau() {
		return this.maxEau;
	}

	/**
	 * Retourne la quantité minimale en eau de l'entité.
	 * 
	 * @return la quantité minimale en eau de l'entité
	 */
	public int obtientMinEau() {
		return this.minEau;
	}

	/**
	 * Retourne la Santé maximale de l'entité.
	 * 
	 * @return la Santé maximale de l'entité
	 */
	public int obtientMaxSante() {
		return this.maxSante;
	}

	/**
	 * Retourne la Santé actuelle de l'entité.
	 * 
	 * @return la Santé actuelle de l'entité
	 */
	public int obtientSante() {
		return this.sante;
	}

	/**
	 * Retourne la quantité d'eau actuelle de l'entité.
	 * 
	 * @return la quantité d'eau actuelle de l'entité
	 */
	public int obtientJaugeEau() {
		return this.jaugeEau;
	}

	/**
	 * Retourne le facteur de perte d'eau de l'entité.
	 * 
	 * @return le facteur de perte d'eau de l'entité
	 */
	public int obtientFacteurPerteEau() {
		return this.facteurPerteEau;
	}
	
	/**
	 * Retourne la durée de vie de l'entité
	 * 
	 * @return la durée de vie de l'entité
	 */
	public int obtientDureeVie() {
		return this.dureeVie;
	}

	// "Setteurs"

	/**
	 * Assigne une nouvelle santé à l'entité
	 * 
	 * @param maSante
	 *            La santé actuelle de l'entité
	 */
	public void assigneSante(int maSante) {
		this.sante = maSante;
	}

	/**
	 * Assigne une nouvelle Position à l'entité
	 * 
	 * @param maPosition
	 *            La position actuelle de l'entité
	 */
	public void assignePosition(Position maPosition) {
		this.maPosition = maPosition;
	}

	/**
	 * Assigne une nouvelle Jauge d'Eau à l'entité
	 * 
	 * @param maJaugeEau
	 *            La jauge d'eau actuelle de l'entité
	 */
	public void assigneJaugeEau(int maJaugeEau) {
		this.jaugeEau = maJaugeEau;
	}
	
	/**
	 * Assigne une nouvelle durée de vie à l'entité
	 * @param ma duree de vie
	 * 			La duree de vie actuelle de l'entité
	 */
	public void assigneDureeVie(int maDureeVie){
		this.dureeVie = maDureeVie;
	}

	// Méthodes

	/**
	 * Calcule la perte d'eau de l'entité
	 * 
	 * @param facteurExterieur
	 *            Le facteur extérieur de perte d'eau
	 */
	public void calculPerteEau(int facteurExterieur) {
		this.jaugeEau = this.jaugeEau* (1 - (facteurExterieur * this.facteurPerteEau));
	}

	/**
	 * Calcul la santé de la plante en fonction de l'eau : -si la santé est inf
	 * à 0, la plante meure -plus jauge d'eau est inférieure au minimum eau,
	 * plus la santé décroit rapidement. On prend aussi en compte la déviation
	 * de la santé par rapport à la santé maximum -plus jauge d'eau est
	 * supérieure au maximum eau, plus la santé décroit rapidement. On prend
	 * aussi en compte la déviation de la santé par rapport à la santé maximum
	 * -plus la jauge eau est prochaine de la moyenne max eau min eau et plus la
	 * sante va augmenter -si la gain de sante entraine un dépassement de la
	 * santé max, alors on retourne santé max
	 * 
	 * @return la santé de la plante en fonction de l'eau
	 */
	public int calculSanteEau() {
		// l'entité meurt de soif :'(
		if (obtientJaugeEau() <= 0) {
			return 0;
		}

		// l'entité n'a pas assez d'eau et perd de la santée
		if (obtientJaugeEau() < obtientMinEau()) {
			return obtientSante()
					- ((obtientMaxSante() / obtientSante()) * (obtientMinEau() - obtientJaugeEau()
							/ obtientMinEau()));
		}

		// l'entité a trop d'eau et perd de la santé
		if (obtientJaugeEau() > obtientMaxEau()) {
			return obtientSante()
					- ((obtientMaxSante() / obtientSante()) * (obtientMaxEau() - obtientJaugeEau()
							/ obtientMaxEau()));
		}
		
		// l'entité a une valeur de sa jauge d'eau comprise entre min eau et max
		// eau, elle gagne une quantité de santé qui dépend de l'écart entre la
		// jauge eau et l'hydro optimale

		// hydroOptim est l'hydrométrie moyenne de l'entité i.e. la moyenne
		// entre MinEau et MaxEau
		int hydroOptim = (obtientMaxEau() + obtientMinEau() / 2);
		int nouvelleSante = (int) (obtientSante()
				/ ((Math.abs(hydroOptim - obtientJaugeEau()) + 0.0001)) + obtientSante());
		// int nouvelleSante = obtientSante()+ (1 / (Math.pow(hydroOptim -
		// obtientJaugeEau(), 2) + (1/hydroOptim)))

		if (nouvelleSante > obtientMaxSante()) {
			return obtientMaxSante();
		}
		return nouvelleSante;
	}

	/**
	 * Méthode permettant de gerer la baisse d'eau et le calcul de la santé liée
	 */
	public void gestionEau()
	{
		// je commence par calculer la perte d'eau
		this.calculPerteEau(0);
		// je diminue la vie de mon entité en fonction de la perte d'eau
		this.assigneSante(this.calculSanteEau());
	}
	
	/**
	 * teste si l'entité est vivante
	 * 
	 * @return true si elle est vivante, false si elle morte
	 */
	public boolean estVivant() {
		if (obtientSante() > 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * calcule la nouvelle duree de vie de l'entite
	 * 
	 * @return l'age de l'entite
	 */
	public void vieillessement(){
		int ageTemporaire = this.obtientDureeVie()-1;
		if(ageTemporaire==0){
			this.assigneSante(0);
		}
		else{
			this.assigneDureeVie(ageTemporaire);
		}
	}
	
	/**
	 * Methode permettant de creer une representation textuelle de l'objet
	 * structure: sante + jaugeEau + dureeVie
	 * 
	 * @return le representation de l'objet
	 */
	public String toString()
	{
		String myString = new String("");
		
		myString+=" : "+this.sante;
		myString+=" : "+this.jaugeEau;
		myString+=" : "+this.dureeVie;
		
		return myString; 
	}
}
